﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once

#include "OwnerPtr.h"
#include "DebugMessage.h"

#define NEW_AS_OWNER_PTR(TYPE, ...) gcmp::OwnerPtr<TYPE>(new TYPE(__VA_ARGS__))
#define NEW_AS_RES_PTR(TYPE, ...) gcmp::ResPtr<TYPE>(new TYPE(__VA_ARGS__))
#define NEW_AS_GGP_OWNER_PTR(TYPE, ...) gcmp::GgpOwnerPtr<TYPE>(new TYPE(__VA_ARGS__))
#define NEW_AS_SHARED_PTR(TYPE, ...) std::shared_ptr<TYPE>(new TYPE(__VA_ARGS__))
#define NEW_AS_CREF_PTR(TYPE, ...) ggp::CRefPtr<TYPE>(new TYPE(__VA_ARGS__))

#pragma region SAFE_DEFINE_OWNER_PTR
#define SAFE_DEFINE_OWNER_PTR_RETURN_VOID_UNLESS(ownerPtr, TYPE, ...) \
    gcmp::OwnerPtr<TYPE> ownerPtr(new TYPE(__VA_ARGS__)); \
    DBG_WARN_AND_RETURN_VOID_UNLESS(ownerPtr, L"New returns nullptr", L"liangcw", L"2022-10-14");

#define SAFE_DEFINE_OWNER_PTR_RETURN_FALSE_UNLESS(ownerPtr, TYPE, ...) \
    gcmp::OwnerPtr<TYPE> ownerPtr(new TYPE(__VA_ARGS__)); \
    DBG_WARN_AND_RETURN_FALSE_UNLESS(ownerPtr, L"New returns nullptr", L"liangcw", L"2022-10-14");

#define SAFE_DEFINE_OWNER_PTR_RETURN_NULLPTR_UNLESS(ownerPtr, TYPE, ...) \
    gcmp::OwnerPtr<TYPE> ownerPtr(new TYPE(__VA_ARGS__)); \
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(ownerPtr, L"New returns nullptr", L"liangcw", L"2022-10-14");

#define SAFE_DEFINE_OWNER_PTR_RETURN_UNLESS(ownerPtr, returnValue, TYPE, ...) \
    gcmp::OwnerPtr<TYPE> ownerPtr(new TYPE(__VA_ARGS__)); \
    DBG_WARN_AND_RETURN_UNLESS(ownerPtr, returnValue, L"New returns nullptr", L"liangcw", L"2022-10-14");
#pragma endregion

#pragma region CHAINED_CALL
/*
 * 目前支持的指针链式调用宏有四种：
 *      1) CHAINED_CALL_AND_RETURN_VOID_UNLESS(TYPE, value, ...)
 *      2) CHAINED_CALL_AND_RETURN_FALSE_UNLESS(TYPE, value, ...)
 *      3) CHAINED_CALL_AND_RETURN_NULLPTR_UNLESS(TYPE, value, ...)
 *      4) CHAINED_CALL_AND_RETURN_UNLESS(TYPE, value, debugWarnReturnValue, ...)
 *
 * 使用约定：
 *      1) 目前指针链式调用宏仅支持最高三层链式调用，超过三层请拆解后使用宏，或后续按需对宏进行扩展
 *      2) 通过指针调用的函数由开发者自行保证为可调用成员函数，否则会编译报错
 *      3）若TYPE为指针类型，宏不对返回的value值进行空指针检测
 *
 * 使用范例，详见TestChainedCall.cpp：
 *      IUiView* pUIView = IUiDocumentViewManager::Get()->GetCurrentUiView();
 *      等价于 CHAINED_CALL_AND_RETURN_VOID_UNLESS(IUiView*, pUIView, IUiDocumentViewManager::Get(), GetCurrentUiView());
 *
 *      IDocument* pDoc = IDocumentManager::Get()->CreateDocument(DocumentType::ProjectDocument, L"test1", nullptr);
 *      等价于 CHAINED_CALL_AND_RETURN_VOID_UNLESS(IDocument*, pDoc, IDocumentManager::Get(), CreateDocument(DocumentType::ProjectDocument, L"test1", nullptr));
 *
 *      IDocument* pDocument = IUiDocumentViewManager::Get()->GetCurrentUiView()->GetUiDocument()->GetDbDocument();
 *      等价于 CHAINED_CALL_AND_RETURN_VOID_UNLESS(IDocument*, pDocument, IUiDocumentViewManager::Get(), GetCurrentUiView(), GetUiDocument(), GetDbDocument());
 */

#define EXPAND( x ) x
#define GET_MACRO(_1, _2, _3, _4, NAME, ...) NAME

/*
 * // 模拟：IElement* pElement = pModelLine->GetOwnerElement();
 * CHAINED_CALL_AND_RETURN_VOID_UNLESS(IElement*, pElement, pModelLine, GetOwnerElement());
 *
 * // 模拟：IElementBasicInformation* pBasicInfo = pModelLine->GetOwnerElement()->GetBasicInformation();
 * CHAINED_CALL_AND_RETURN_VOID_UNLESS(IElementBasicInformation*, pBasicInfo, pModelLine, GetOwnerElement(), GetBasicInformation());
 *
 * // 模拟：IDocument* pCurrentDoc = pModelLine->GetOwnerElement()->GetBasicInformation()->GetDocument();
 * CHAINED_CALL_AND_RETURN_VOID_UNLESS(IDocument*, pCurrentDoc, pModelLine, GetOwnerElement(), GetBasicInformation(), GetDocument());
 *
 * 其它使用范例参照GbmpNew.h
 */
#define CHAINED_CALL_AND_RETURN_VOID_UNLESS(TYPE, value, ...) \
    EXPAND(GET_MACRO(__VA_ARGS__, PRIVATE_RETURN_VOID_HANDLE_FOUR_ARGS, PRIVATE_RETURN_VOID_HANDLE_THREE_ARGS, PRIVATE_RETURN_VOID_HANDLE_TWO_ARGS)(TYPE, value, __VA_ARGS__));

/*
 * // 模拟：IElement* pElement = pModelLine->GetOwnerElement();
 * CHAINED_CALL_AND_RETURN_FALSE_UNLESS(IElement*, pElement, pModelLine, GetOwnerElement());
 *
 * // 模拟：IElementBasicInformation* pBasicInfo = pModelLine->GetOwnerElement()->GetBasicInformation();
 * CHAINED_CALL_AND_RETURN_FALSE_UNLESS(IElementBasicInformation*, pBasicInfo, pModelLine, GetOwnerElement(), GetBasicInformation());
 *
 * // 模拟：IDocument* pCurrentDoc = pModelLine->GetOwnerElement()->GetBasicInformation()->GetDocument();
 * CHAINED_CALL_AND_RETURN_FALSE_UNLESS(IDocument*, pCurrentDoc, pModelLine, GetOwnerElement(), GetBasicInformation(), GetDocument());
 *
 * 其它使用范例参照GbmpNew.h
 */
#define CHAINED_CALL_AND_RETURN_FALSE_UNLESS(TYPE, value, ...) \
    EXPAND(GET_MACRO(__VA_ARGS__, PRIVATE_RETURN_FALSE_HANDLE_FOUR_ARGS, PRIVATE_RETURN_FALSE_HANDLE_THREE_ARGS, PRIVATE_RETURN_FALSE_HANDLE_TWO_ARGS)(TYPE, value, __VA_ARGS__));

/*
 * // 模拟：IElement* pElement = pModelLine->GetOwnerElement();
 * CHAINED_CALL_AND_RETURN_NULLPTR_UNLESS(IElement*, pElement, pModelLine, GetOwnerElement());
 *
 * // 模拟：IElementBasicInformation* pBasicInfo = pModelLine->GetOwnerElement()->GetBasicInformation();
 * CHAINED_CALL_AND_RETURN_NULLPTR_UNLESS(IElementBasicInformation*, pBasicInfo, pModelLine, GetOwnerElement(), GetBasicInformation());
 *
 * // 模拟：IDocument* pCurrentDoc = pModelLine->GetOwnerElement()->GetBasicInformation()->GetDocument();
 * CHAINED_CALL_AND_RETURN_NULLPTR_UNLESS(IDocument*, pCurrentDoc, pModelLine, GetOwnerElement(), GetBasicInformation(), GetDocument());
 *
 * 其它使用范例参照GbmpNew.h
 */
#define CHAINED_CALL_AND_RETURN_NULLPTR_UNLESS(TYPE, value, ...) \
    EXPAND(GET_MACRO(__VA_ARGS__, PRIVATE_RETURN_NULLPTR_HANDLE_FOUR_ARGS, PRIVATE_RETURN_NULLPTR_HANDLE_THREE_ARGS, PRIVATE_RETURN_NULLPTR_HANDLE_TWO_ARGS)(TYPE, value, __VA_ARGS__));

/*
 * // 模拟：IElement* pElement = pModelLine->GetOwnerElement();
 * CHAINED_CALL_AND_RETURN_UNLESS(IElement*, pElement, DEBUG_WARN_RETURN_VALUE, pModelLine, GetOwnerElement());
 *
 * // 模拟：IElementBasicInformation* pBasicInfo = pModelLine->GetOwnerElement()->GetBasicInformation();
 * CHAINED_CALL_AND_RETURN_UNLESS(IElementBasicInformation*, pBasicInfo, DEBUG_WARN_RETURN_VALUE, pModelLine, GetOwnerElement(), GetBasicInformation());
 *
 * // 模拟：IDocument* pCurrentDoc = pModelLine->GetOwnerElement()->GetBasicInformation()->GetDocument();
 * CHAINED_CALL_AND_RETURN_UNLESS(IDocument*, pCurrentDoc, pModelLine, DEBUG_WARN_RETURN_VALUE, GetOwnerElement(), GetBasicInformation(), GetDocument());
 *
 * 其它使用范例参照GbmpNew.h
 */
#define CHAINED_CALL_AND_RETURN_UNLESS(TYPE, value, debugWarnReturnValue, ...) \
    EXPAND(GET_MACRO(__VA_ARGS__, PRIVATE_RETURN_HANDLE_FOUR_ARGS, PRIVATE_RETURN_HANDLE_THREE_ARGS, PRIVATE_RETURN_HANDLE_TWO_ARGS)(TYPE, value, debugWarnReturnValue, __VA_ARGS__));


// PRIVATE_RETURN_VOID_UNLESS
#define PRIVATE_RETURN_VOID_HANDLE_TWO_ARGS(TYPE, value, arg1, arg2) \
    DBG_WARN_AND_RETURN_VOID_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    TYPE value = arg1->arg2;

#define PRIVATE_RETURN_VOID_HANDLE_THREE_ARGS(TYPE, value, arg1, arg2, arg3) \
    DBG_WARN_AND_RETURN_VOID_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    PRIVATE_RETURN_VOID_HANDLE_TWO_ARGS(TYPE, value, arg1->arg2, arg3);

#define PRIVATE_RETURN_VOID_HANDLE_FOUR_ARGS(TYPE, value, arg1, arg2, arg3, arg4) \
    DBG_WARN_AND_RETURN_VOID_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    PRIVATE_RETURN_VOID_HANDLE_THREE_ARGS(TYPE, value, arg1->arg2, arg3, arg4);


// PRIVATE_RETURN_FALSE_UNLESS
#define PRIVATE_RETURN_FALSE_HANDLE_TWO_ARGS(TYPE, value, arg1, arg2) \
    DBG_WARN_AND_RETURN_FALSE_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    TYPE value = arg1->arg2;

#define PRIVATE_RETURN_FALSE_HANDLE_THREE_ARGS(TYPE, value, arg1, arg2, arg3) \
    DBG_WARN_AND_RETURN_FALSE_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    PRIVATE_RETURN_FALSE_HANDLE_TWO_ARGS(TYPE, value, arg1->arg2, arg3);

#define PRIVATE_RETURN_FALSE_HANDLE_FOUR_ARGS(TYPE, value, arg1, arg2, arg3, arg4) \
    DBG_WARN_AND_RETURN_FALSE_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    PRIVATE_RETURN_FALSE_HANDLE_THREE_ARGS(TYPE, value, arg1->arg2, arg3, arg4);


// PRIVATE_RETURN_NULLPTR_UNLESS
#define PRIVATE_RETURN_NULLPTR_HANDLE_TWO_ARGS(TYPE, value, arg1, arg2) \
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    TYPE value = arg1->arg2;

#define PRIVATE_RETURN_NULLPTR_HANDLE_THREE_ARGS(TYPE, value, arg1, arg2, arg3) \
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    PRIVATE_RETURN_NULLPTR_HANDLE_TWO_ARGS(TYPE, value, arg1->arg2, arg3);

#define PRIVATE_RETURN_NULLPTR_HANDLE_FOUR_ARGS(TYPE, value, arg1, arg2, arg3, arg4) \
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(arg1 != nullptr, L"nullptr check failed", L"peibc", L"2022-12-07");\
    PRIVATE_RETURN_NULLPTR_HANDLE_THREE_ARGS(TYPE, value, arg1->arg2, arg3, arg4);


// PRIVATE_RETURN_UNLESS
#define PRIVATE_RETURN_HANDLE_TWO_ARGS(TYPE, value, returnValue, arg1, arg2) \
    DBG_WARN_AND_RETURN_UNLESS(arg1 != nullptr, returnValue, L"nullptr check failed", L"peibc", L"2022-12-07");\
    TYPE value = arg1->arg2;

#define PRIVATE_RETURN_HANDLE_THREE_ARGS(TYPE, value, returnValue, arg1, arg2, arg3) \
    DBG_WARN_AND_RETURN_UNLESS(arg1 != nullptr, returnValue, L"nullptr check failed", L"peibc", L"2022-12-07");\
    PRIVATE_RETURN_HANDLE_TWO_ARGS(TYPE, value, returnValue, arg1->arg2, arg3);

#define PRIVATE_RETURN_HANDLE_FOUR_ARGS(TYPE, value, returnValue, arg1, arg2, arg3, arg4) \
    DBG_WARN_AND_RETURN_UNLESS(arg1 != nullptr, returnValue, L"nullptr check failed", L"peibc", L"2022-12-07");\
    PRIVATE_RETURN_HANDLE_THREE_ARGS(TYPE, value, returnValue, arg1->arg2, arg3, arg4);
#pragma endregion

// 只能用在不能使用OwnerPtr的地方
#define NEW_AS_UNIQUE_PTR(TYPE, ...) std::unique_ptr<TYPE>(new TYPE(__VA_ARGS__))


// QT only
#define NEW_AS_QT_CHILD(TYPE, ...) \
    ([=]()->TYPE*{ \
        static_assert(std::is_base_of<QObject, TYPE>::value, "only QT object is supported."); \
        TYPE* pQtChild = new TYPE(__VA_ARGS__); \
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(nullptr != pQtChild && pQtChild->parent(), L"parent cannot be null", L"周智华", L"2016/09/27"); \
        return pQtChild; \
    }())

// QT only  parent可以为nullptr
#define NEW_AS_QT(TYPE, ...) \
    ([=]()->TYPE*{ \
        TYPE* pQtChild = new TYPE(__VA_ARGS__); \
        return pQtChild; \
    }())

// Qt 
// new and assure not nullptr
#define NEW_AS_QT_IF_NULL_DBG_WARN_AND_RETURN_VOID(qtPtr, TYPE, ...) \
    TYPE* qtPtr = NEW_AS_QT(TYPE, __VA_ARGS__); \
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != qtPtr, L"The Qt Object has not been constructed successfully!", L"wuzx-d", L"2022-11-23");

#define NEW_AS_QT_IF_NULL_DBG_WARN_AND_RETURN_FALSE(qtPtr, TYPE, ...) \
    TYPE* qtPtr = NEW_AS_QT(TYPE, __VA_ARGS__); \
    DBG_WARN_AND_RETURN_FALSE_UNLESS(nullptr != qtPtr, L"The Qt Object has not been constructed successfully!", L"wuzx-d", L"2022-11-23");

#define NEW_AS_QT_IF_NULL_DBG_WARN_AND_RETURN_NULLPTR(qtPtr, TYPE, ...) \
    TYPE* qtPtr = NEW_AS_QT(TYPE, __VA_ARGS__); \
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(nullptr != qtPtr, L"The Qt Object has not been constructed successfully!", L"wuzx-d", L"2022-11-23");

#define NEW_AS_QT_IF_NULL_DBG_WARN_AND_RETURN(qtPtr, returnVal, TYPE, ...) \
    TYPE* qtPtr = NEW_AS_QT(TYPE, __VA_ARGS__); \
    DBG_WARN_AND_RETURN_UNLESS(nullptr != qtPtr, returnVal, L"The Qt Object has not been constructed successfully!", L"wuzx-d", L"2022-11-23");

// 非顶层QLayout对象创建的时候没有parent，后面需要调用QLayout::addLayout()或者QWidget::setLayout()添加parent
#define NEW_AS_QT_LAYOUT(TYPE, ...) \
    ([=]()->TYPE*{ \
        static_assert(std::is_base_of<QLayout, TYPE>::value, "only QLayout object is supported."); \
        TYPE* pQLayout = new TYPE(__VA_ARGS__); \
        return pQLayout; \
    }())

#define DELETE_QTREEWIDGET_CHILDREN(pTreeWidgetItem) \
    if(pTreeWidgetItem != nullptr) \
    { \
        QList<QTreeWidgetItem*> children = pTreeWidgetItem->takeChildren(); \
        int childCount = children.count(); \
        for (int childIndex = 0; childIndex < children.count(); childIndex++) \
        { \
            delete children[childIndex]; \
        } \
        children.clear(); \
    }
